package com.strato.rule.deploy.v1_0_0;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.osgi.framework.Bundle;

import com.strato.annotation.base.v1_0_0.handler.AbstractAnnotationHandler;
import com.strato.annotation.base.v1_0_0.registry.ClassDescriptor;
import com.strato.annotation.osgi.v1_0_0.service.OsgiService;
import com.strato.annotation.osgi.v1_0_0.service.OsgiWired;
import com.strato.annotation.osgi.v1_0_0.service.util.ServiceCreator;
import com.strato.logging.v1_0_0.api.Log;
import com.strato.rule.core.v1_0_0.annotation.RuleClass;
import com.strato.rule.core.v1_0_0.annotation.RuleFunction;
import com.strato.rule.core.v1_0_0.execution.Rule;
import com.strato.rule.core.v1_0_0.execution.RuleEngine;
import com.strato.rule.core.v1_0_0.execution.Session;

@OsgiService
public class RuleAnnotationHandler extends AbstractAnnotationHandler implements RuleEngine {

	@OsgiWired
	private Log log;
	
	private Map<String,Rule> rules=new TreeMap<String,Rule>();
	
	@Override
	public void onDiscoverClass(Bundle bundle, Class<?> clazz, ClassDescriptor classDescriptor) {
		if(!clazz.isAnnotationPresent(RuleClass.class)){
			return;
		}
		Object service = ServiceCreator.newInstance(bundle, clazz);
		Method[] methods = clazz.getMethods();
		for(Method method:methods){
			if(!method.isAnnotationPresent(RuleFunction.class)){
				continue;
			}
			RuleFunction function = method.getAnnotation(RuleFunction.class);
			String id=function.id();
			Object owner=null;
			if(!Modifier.isStatic(method.getModifiers())){
				owner=service;
			}
			Rule rule=new Rule(owner,bundle,clazz,method);
			rules.put(id, rule);
			log.info("Deployed Rule "+rule);
		}
	}

	@Override
	public void handleUnresolveClass(Bundle bundle, ClassDescriptor classDescriptor) {
		HashMap<String, Rule> map = new HashMap<String,Rule>(rules);
		for(Iterator<Entry<String, Rule>> iter = map.entrySet().iterator();iter.hasNext();){
			Entry<String, Rule> entry = iter.next();
			String id=entry.getKey();
			Rule rule=entry.getValue();
			if(rule.getBundle().getSymbolicName().equals(bundle.getSymbolicName())&&rule.getClazz().getName().equals(classDescriptor.getClassName())){
				rules.remove(id);
			}
			log.info("Undeployed Rule "+rule);
		}
	}

	@Override
	public Rule getRule(String id) {
		return rules.get(id);
	}

	@Override
	public Session newSession() {
		return new Session(this);
	}

	@Override
	public List<Rule> getByGroup(String ruleGroup) {
		List<Rule> result=new ArrayList<Rule>();
		for(Rule rule:rules.values()){
			RuleFunction rf = rule.getMethod().getAnnotation(RuleFunction.class);
			String group=rf.group();
			if(group.equals(ruleGroup)){
				result.add(rule);
			}
		}
		return result;
	}
	
}
